#ifndef FlixMatrix_FastFile_h
#define FlixMatrix_FastFile_h

#include <string>

class FastOFile {
public:
    explicit FastOFile(const std::string& filename, int bufferSize = 1024);
    ~FastOFile();

    void open();
    void close();
    void flush();
    
    void write(const void* data, int bytesToWrite);

    bool operator!() const {
        return 0 == file_;
    }

    operator bool() const {
        return 0 != file_;
    }

    template <typename ValueT>
    FastOFile& operator<<(const ValueT& value) {
        write(&value, sizeof(ValueT));
        return *this;
    }
    
private:
    int bufferSpace() const;
    void* curBufferPos() const;
    void appendToBuffer(const void* data, int length);

private:
    std::string filename_;
    void* buffer_;
    int bufferSize_;
    int buffOffset_;
    FILE* file_;

private:
    FastOFile(const FastOFile&);
    FastOFile& operator=(const FastOFile&);
};

class FastIFile {
public:
    explicit FastIFile(const std::string& name, int bufferSize = 1024);
    ~FastIFile();
    
    void open();
    void close();
    
    int read(void* data, int bytesToRead);
    
    bool operator!() const {
        return 0 == file_;
    }

    operator bool() const {
        return 0 != file_;
    }

    template <typename ValueT>
    FastIFile& operator>>(ValueT& value) {
        read(&value, sizeof(ValueT));
        return *this;
    }

private:
    void readToBuffer();
    void readFromBuffer(void* data, int bytesToRead);
    int unreadBufferLen() const;
    
private:
    std::string filename_;
    void* buffer_;
    void* headPos_;
    int bufferSize_;
    int bufferUsed_;
    FILE* file_;
    int remainFileSize_;

private:
    FastIFile(const FastIFile&);
    FastIFile& operator=(const FastIFile&);
};

#endif // FlixMatrix_FastFile_h